<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>HuanYingPan API 接口文档</title>
  <style>
    :root { --bg:#0f172a; --panel:#111827; --text:#e5e7eb; --muted:#9ca3af; --accent:#22c55e; --code:#0b1020; }
    html,body { background:var(--bg); color:var(--text); font:14px/1.7 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Apple Color Emoji","Segoe UI Emoji"; margin:0; }
    .wrap { max-width: 980px; margin: 0 auto; padding: 32px 16px; }
    .card { background: var(--panel); border: 1px solid #1f2937; border-radius: 12px; padding: 24px; box-shadow: 0 8px 24px rgba(0,0,0,.25); }
    h1 { font-size: 26px; margin: 0 0 12px; }
    h2 { font-size: 20px; margin: 24px 0 12px; padding-top: 6px; border-top: 1px dashed #1f2937; }
    h3 { font-size: 16px; margin: 18px 0 8px; }
    p,li { color: var(--text); }
    .muted { color: var(--muted); }
    code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
    code { background: #0f1a2f; color:#cbd5e1; padding: 2px 6px; border-radius: 6px; }
    pre { background: var(--code); color:#cbd5e1; border:1px solid #1f2937; border-radius: 10px; padding: 14px; overflow:auto; }
    .kvs { display:grid; grid-template-columns: 160px 1fr; gap: 8px 16px; }
    .tag { display:inline-block; padding:2px 8px; border-radius: 999px; border:1px solid #334155; color:#a1a1aa; font-size:12px; }
    a { color:#93c5fd; text-decoration:none; }
    a:hover { text-decoration:underline; }
    ul { margin:8px 0 8px 20px; }
  </style>
</head>
<body>
  <div class="wrap">
    <div class="card">
      <h1>HuanYingPan API 接口文档</h1>
      <p class="muted">根目录 <code>api.php</code> 的上传接口说明，所有返回为 JSON。</p>

      <h2>基本信息</h2>
      <div class="kvs">
        <div>Base URL</div><div><code>https://&lt;你的域名&gt;/api.php</code></div>
        <div>方法</div><div><span class="tag">POST</span></div>
        <div>编码</div><div>UTF-8</div>
        <div>协议</div><div>HTTPS（推荐）</div>
        <div>CORS</div><div>允许跨域，请求头允许 <code>Content-Type, X-API-Key</code></div>
      </div>

      <h2>认证</h2>
      <p>使用 API Key 认证，客户端必须携带有效 <code>apikey</code>。</p>
      <ul>
        <li>请求头：<code>X-API-Key: &lt;apikey&gt;</code>（推荐）</li>
        <li>或表单字段：<code>apikey=&lt;apikey&gt;</code></li>
      </ul>
      <p>服务端以 <code>pre_user.api_key</code> 定位用户，校验启用状态，并按用户所属权限组选择云存储。</p>

      <h2>环境与站点限制</h2>
      <ul>
        <li><code>conf['api_open']</code> 为 0 时：<code>{"code":-4,"msg":"当前站点未开启上传API"}</code></li>
        <li><code>conf['api_referer']</code> 配置来源白名单时校验 <code>HTTP_REFERER</code> 的 host。</li>
        <li>仅允许 <code>POST</code>，其他方法返回：<code>{"code":-4,"msg":"请求方法不允许"}</code></li>
      </ul>

      <h2>上传文件</h2>
      <h3>URL</h3>
      <p><code>POST /api.php</code>（<code>Content-Type: multipart/form-data</code>）</p>

      <h3>请求头</h3>
      <ul>
        <li><code>X-API-Key: &lt;apikey&gt;</code>（与表单二选一，必须提供）</li>
      </ul>

      <h3>表单参数</h3>
      <ul>
        <li><code>file</code>（必填）：上传文件</li>
        <li><code>apikey</code>（必填/或用请求头替代）</li>
        <li><code>show</code>（可选）：<code>1</code> 公开；默认隐藏</li>
        <li><code>ispwd</code>（可选）：<code>1</code> 启用下载密码</li>
        <li><code>pwd</code>（可选）：当 <code>ispwd=1</code> 时必填，仅字母数字</li>
      </ul>

      <h3>行为与校验</h3>
      <ul>
        <li>体积限制：当 <code>conf['upload_size'] &gt; 0</code> 超限即返回错误</li>
        <li>类型/名称黑名单：匹配 <code>conf['type_block']</code>、<code>conf['name_block']</code> 拒绝上传</li>
        <li>重复文件：站点已存在相同哈希（<code>md5_file</code>）时直接返回已存在信息</li>
        <li>云存储选择：按用户所属权限组选择存储（未配置则回退站点默认 <code>conf['storage']</code>），写入文件表 <code>storage</code></li>
        <li>归属记录：写入 <code>uid</code> 到 <code>pre_file</code></li>
        <li>风控：图片涉敏 <code>block=1</code>；视频待审 <code>block=2</code></li>
      </ul>

      <h3>成功返回（新文件）</h3>
      <pre>{
  "code": 0,
  "msg": "文件上传成功！",
  "exists": 0,
  "hash": "3c75c279a1fda2ce695c64326b2e7472",
  "name": "example.png",
  "size": 12345,
  "type": "png",
  "id": 1001,
  "downurl": "https://example.com/down.php/3c75c279a1fda2ce695c64326b2e7472.png",
  "viewurl": "https://example.com/view.php/3c75c279a1fda2ce695c64326b2e7472.png",
  "uid": 42,
  "storage": "oss"
}</pre>

      <h3>成功返回（已存在）</h3>
      <pre>{
  "code": 0,
  "msg": "本站已存在该文件",
  "exists": 1,
  "hash": "3c75c279a1fda2ce695c64326b2e7472",
  "name": "example.png",
  "size": 12345,
  "type": "png",
  "id": 1001,
  "downurl": "https://example.com/down.php/3c75c279a1fda2ce695c64326b2e7472.png",
  "viewurl": "https://example.com/view.php/3c75c279a1fda2ce695c64326b2e7472.png",
  "uid": 42,
  "storage": "oss"
}</pre>

      <h3>常见失败</h3>
      <ul>
        <li>缺少 apikey：<code>{"code":-3,"msg":"缺少 apikey 参数"}</code></li>
        <li>apikey 无效或用户禁用：<code>{"code":-2,"msg":"apikey 无效或用户不存在/已禁用"}</code></li>
        <li>来源错误：<code>{"code":-4,"msg":"来源地址不正确"}</code></li>
        <li>体积超限：<code>{"code":-1,"msg":"文件大小超过限制（最大 50MB）"}</code></li>
        <li>类型/名称黑名单：<code>{"code":-1,"msg":"文件上传失败","error":"block"}</code></li>
        <li>存储失败：<code>{"code":-1,"msg":"文件上传失败","error":"stor"}</code></li>
        <li>数据库失败：<code>{"code":-1,"msg":"上传失败&lt;错误信息&gt;","error":"database"}</code></li>
        <li>未开启 API：<code>{"code":-4,"msg":"当前站点未开启上传API"}</code></li>
        <li>方法不允许：<code>{"code":-4,"msg":"请求方法不允许"}</code></li>
        <li>用户表缺少 <code>api_key</code> 字段：<code>{"code":-5,"msg":"未检测到用户表 api_key 字段"}</code></li>
      </ul>

      <h3>curl 示例</h3>
      <pre>curl -X POST \
  -H "X-API-Key: &lt;你的apikey&gt;" \
  -F "file=@/path/to/file.png" \
  -F "show=1" \
  -F "ispwd=1" \
  -F "pwd=Abc123" \
  https://example.com/api.php</pre>

      <h2>字段说明</h2>
      <ul>
        <li><code>code</code>：状态码，<code>0</code> 成功，负数失败</li>
        <li><code>msg</code>：提示信息</li>
        <li><code>exists</code>：是否已有同哈希文件（1/0）</li>
        <li><code>hash</code>：文件 MD5</li>
        <li><code>name</code>：文件名</li>
        <li><code>size</code>：文件大小（字节）</li>
        <li><code>type</code>：扩展名</li>
        <li><code>id</code>：文件表主键</li>
        <li><code>downurl</code>：下载地址（若设置密码以 <code>&amp;pwd</code> 追加）</li>
        <li><code>viewurl</code>：在线预览地址（部分类型）</li>
        <li><code>uid</code>：归属用户 ID</li>
        <li><code>storage</code>：云存储类型（local/oss/qcloud/obs/upyun/qiniu）</li>
        <li><code>block</code>：库内风控标记（图片涉敏=1，视频待审=2）</li>
      </ul>

      <h2>部署准备</h2>
      <ul>
        <li>为 <code>pre_user</code> 增加唯一 API Key 字段：<code>ALTER TABLE pre_user ADD COLUMN api_key VARCHAR(64) UNIQUE;</code></li>
        <li>为用户生成 apikey（示例）：<code>UPDATE pre_user SET api_key=MD5(CONCAT(uid,'-',UUID())) WHERE uid=&lt;UID&gt;;</code></li>
        <li>在权限组配置云存储类型；未配置则使用站点默认</li>
      </ul>

      <h2>安全建议</h2>
      <ul>
        <li>强制使用 HTTPS</li>
        <li>优先通过请求头传递 apikey</li>
        <li>限制上传类型/体积并定期轮换 apikey</li>
      </ul>

      <p class="muted">版本：2025-10-23（新增 apikey 认证，按用户组动态云存储，统一 JSON 返回）</p>
    </div>
  </div>
</body>
</html>